package procilege.compiler;

import java.io.IOException;
import java.io.StringReader;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.namespace.QName;

import org.antlr.runtime.ANTLRReaderStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.CommonTreeNodeStream;

import procilege.antlr.PalEval;
import procilege.antlr.PalExprLexer;
import procilege.antlr.PalExprParser;
import procilege.lang.ScopeBlock;

import com.google.inject.Inject;
import com.google.inject.Injector;

public class PalCompiler {
	final public static String DEFAULT_NS_URI = "urn:procilege:global";

	@Inject
	private Logger logger;

	@Inject
	private Injector guiceIejector;

	public void compile(QName cid, StringReader reader) {

		ANTLRReaderStream input = null;

		try {
			input = new ANTLRReaderStream(reader);
		} catch (IOException e) {
			throw new PalParserException(e);
		}

		PalExprLexer lexer = new PalExprLexer(input);
		CommonTokenStream tokens = new CommonTokenStream(lexer);
		PalExprParser parser = new PalExprParser(tokens);
		PalExprParser.prog_return r = null;

		try {
			r = parser.prog();
		} catch (RecognitionException e) {
			throw new PalParserException(e);
		}

		// walk through the tree
		CommonTree t = (CommonTree) r.getTree();

		if (logger.isLoggable(Level.FINEST)) {
			StringBuilder sb = new StringBuilder();
			sb.append("compiled the pal content:\n");
			sb.append(">>>> abstract syntax tree:\n");
			sb.append(t.toStringTree());
			logger.finest(sb.toString());
		}

		CommonTreeNodeStream nodes = new CommonTreeNodeStream(t);
		PalEval walker = new PalEval(nodes);
		guiceIejector.injectMembers(walker);

		ScopeBlock scope = new ScopeBlock();
		guiceIejector.injectMembers(scope);
		if (cid == null)
			scope.registerNamespace(PalCompiler.DEFAULT_NS_URI, null);
		else
			// use the namespace of the content as the default scope
			scope.registerNamespace(cid.getNamespaceURI(), null);

		try {
			walker.prog(scope);
		} catch (RecognitionException e) {
			throw new PalEvalutionException(e);
		}
	}
}
